package com.cross.mysql;

import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.dom4j.DocumentException;

import com.cross.core.AbstractReader;
import com.cross.core.Column;
import com.cross.core.Header;
import com.cross.core.Item;
import com.cross.core.Row;
import com.cross.util.StringUtils;
import com.cross.util.ItemType;
/**
 * jdbc读入器
 * @author www
 *
 */
public class SimpleMySQLJdbcReader extends AbstractReader {
	//sql语句
	private String sql;
	//数据库连接
	private Connection conn;
	//结果集
	private ResultSet rs;
	//元数据结果集
	private ResultSetMetaData rsmd;
	//cross数据类型与jdbc数据类型的一个映射
	private Map<String, String> typeMap;
	
	/**
	 * 构造方法
	 */
	public SimpleMySQLJdbcReader(String sql, Connection conn) throws FileNotFoundException,
			DocumentException, SQLException {
		this.sql = sql;
		this.conn = conn;
		typeMap = getTypeMap();
		
		rs = conn.createStatement().executeQuery(sql);
		rsmd = rs.getMetaData();
		header = getHeader(rsmd);
		
		int a = sql.indexOf(" from ");
		a = sql.indexOf(" ", a+5);
		int b = sql.indexOf(" ", a+1);
		String temp = sql.substring(a+1, b);
		temp = temp.trim();
		header.setObjectName(temp);
	}

	/**
	 * 构造方法
	 * @return 
	 */
	public SimpleMySQLJdbcReader(String objectName, String sql, Connection conn) throws FileNotFoundException,
			DocumentException, SQLException {
		this.sql = sql;
		this.conn = conn;
		typeMap = getTypeMap();
		
		rs = conn.createStatement().executeQuery(sql);
		rsmd = rs.getMetaData();
		header = getHeader(rsmd);
		header.setObjectName(objectName);
	}
	/**
	 * 下一行
	 */
	@Override
	protected boolean nextRow() {
		try {
			if (rs.next()) {
				currentRow = toRow(rs);
			} else {
				return false;
			}
		} catch (SQLException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * 将ResultSet转换为Row
	 * @param rs
	 * @return
	 * @throws SQLException
	 */
	private Row toRow(ResultSet rs) throws SQLException {
		Row row = new Row();
		int index = 1;
		for (Column c : header.getColumns()) {
			if(ItemType.TYPE_TIMESTAMP.equalsIgnoreCase(c.getType())){
				row.append(new Item<Object>(rs.getTimestamp(index++), c.getType(), c.getPrecision()));
			} else {
				row.append(new Item<Object>(rs.getObject(index++), c.getType(), c.getPrecision()));
			}
		}
		return row;
	}
	
	/**
	 * 根据ResultSetMetaData获得标题
	 * @param rsmd
	 * @return
	 * @throws SQLException
	 */
	private Header getHeader(ResultSetMetaData rsmd) throws SQLException {
		Header header = new Header();
		int count = rsmd.getColumnCount();
		String type;
		String name;
		header.setObjectName(rsmd.getTableName(1));
		for (int i = 0; i < count; i++) {
			type = rsmd.getColumnTypeName(i+1);
			name = rsmd.getColumnLabel(i+1);
			int precision = rsmd.getPrecision(i+1);
			Column column = new Column(i, name, covertType(type, precision), precision);
			header.add(column);
		}
		return header;
	}

	/**
	 * 转换数据类型
	 * @param type
	 * @return
	 */
	private String covertType(String type, int precision) {
		if (StringUtils.isEmpty(type)) {
			return null;
		}
		if (typeMap.containsKey(type)) {
			if("CHAR".equalsIgnoreCase(type)){
				if(precision == 1){
					return ItemType.TYPE_BOOLEAN;
				} else {
					return ItemType.TYPE_STRING;
				}
			}
			return typeMap.get(type);
		} else {
			throw new RuntimeException("Unknow Field Type:"+type);
		}
	}

	/**
	 * 获得数据类型映射
	 * @return
	 */
	private Map<String, String> getTypeMap() {
		Map<String, String> map = new HashMap<String, String>();
		map.put("CHAR", ItemType.TYPE_CHARACTER);
		map.put("VARCHAR", ItemType.TYPE_STRING);
		map.put("VARCHAR2", ItemType.TYPE_STRING);
		map.put("LONG", ItemType.TYPE_LONG);
		map.put("DATE", ItemType.TYPE_DATE);
		map.put("TIMESTAMP", ItemType.TYPE_TIMESTAMP);
		map.put("TIME", ItemType.TYPE_TIME);
		map.put("NUMBER", ItemType.TYPE_NUMBER);
		return map;
	}

	/**
	 * 关闭
	 */
	@Override
	public void close() {
		try {
			rs.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

}
